/*******************************************************************************
** 文件名称：ds3231.c
** 文件作用：时钟芯片DS3231操作源文件
** 编写作者：Tom Free 付瑞彪
** 编写时间：2018-10-18
** 文件备注：
**
**
** 更新记录：
**          2018-10-18 -> 将以前文件进行整理                         <Tom Free>
**
**          1 Tab == 4 Spaces     UTF-8     ANSI C Language (C99)
*******************************************************************************/

#include "ds3231.h"
#include "i2c.h"

/* 器件地址，最低位为读写控制位*/
#define DS3231_WADDR        0xD0
#define DS3231_RADDR        0xD1

/* 寄存器地址 */
#define DS3231_SEC_ADDR     0x00
#define DS3231_MIN_ADDR     0x01
#define DS3231_HOUR_ADDR    0x02
#define DS3231_DAY_ADDR     0x03
#define DS3231_DATE_ADDR    0x04
#define DS3231_MON_ADDR     0x05
#define DS3231_YEAR_ADDR    0x06
#define DS3231_A1M1_ADDR    0x07
#define DS3231_A1M2_ADDR    0x08
#define DS3231_A1M3_ADDR    0x09
#define DS3231_A1M4_ADDR    0x0A
#define DS3231_A2M2_ADDR    0x0B
#define DS3231_A2M3_ADDR    0x0C
#define DS3231_A2M4_ADDR    0x0D
#define DS3231_CTL_ADDR     0x0E
#define DS3231_CSR_ADDR     0x0F
#define DS3231_OFFS_ADDR    0x10
#define DS3231_TEMH_ADDR    0x11
#define DS3231_TEML_ADDR    0x12

/* 时间结构体定义 */
typedef union
{
    uint8_t data[7];
    struct
    {
        uint8_t sec;
        uint8_t min;
        uint8_t hour;
        uint8_t day;
        uint8_t date;
        uint8_t mon;
        uint8_t year;
    };
} ds3231_time_t;

/* DS3231写入一个字节数据 */
static void ds3231_write_byte(uint8_t addr, uint8_t data)
{
    i2c_start();                    // 产生起始信号
    i2c_write_byte(DS3231_WADDR);   // 写入设备地址（写）
    i2c_write_byte(addr);           // 写入要操作的单元地址
    i2c_write_byte(data);           // 写入数据
    i2c_stop();                     // 产生停止符号
}

/* DS3231读取一个字节数据 */
static uint8_t ds3231_read_byte(uint8_t addr)
{
    uint8_t data;                   // 定义一个缓冲寄存器

    i2c_start();                    // 产生起始信号
    i2c_write_byte(DS3231_WADDR);   // 写入设备地址（写）
    i2c_write_byte(addr);           // 写入要操作的单元地址
    //i2c_stop();                     // 产生停止符号
    i2c_start();                    // 产生起始信号
    i2c_write_byte(DS3231_RADDR);   // 写入设备地址（读）
    data = i2c_read_byte(false);    // 读出数据
    i2c_stop();                     // 产生停止符号

    return data;                    // 返回读取的一个字节数据
}

/* DS3231初始化 */
void ds3231_init(void)
{
    i2c_init();

    // 使能振荡器，备用电源不输出方波，温度转换，
    // SQW输出1HZ方波，不使用内部闹钟
    ds3231_write_byte(DS3231_CTL_ADDR, 0x20);
}

/* 读取DS3231时钟停止标志 */
bool ds3231_get_stop_flag(void)
{
    uint8_t temp = ds3231_read_byte(DS3231_CSR_ADDR);

    return temp & 0x80 ? true : false;
}

/* 清除DS3231时钟停止标志 */
void ds3231_clear_stop_flag(void)
{
    uint8_t temp = ds3231_read_byte(DS3231_CSR_ADDR);

    temp &= ~0x80;

    ds3231_write_byte(DS3231_CSR_ADDR, temp);
}

/* 读取DS3231内部温度 */
int16_t ds3231_read_temprature(void)
{
    uint8_t temp_h, temp_l;
    int16_t temp_ret = 0;

    temp_h = ds3231_read_byte(DS3231_TEMH_ADDR);
    temp_l = ds3231_read_byte(DS3231_TEML_ADDR);

    temp_ret = (int16_t)(((uint16_t)temp_h << 8) | temp_l);
    temp_ret >>= 6;

    return temp_ret;
}

/* 读取DS3231时间 */
void ds3231_read_time(gm_time_t *time)
{
    uint8_t temp;

    temp = ds3231_read_byte(DS3231_SEC_ADDR);
    time->second = GM_BCD_TO_HEX(temp) % 60;

    temp = ds3231_read_byte(DS3231_MIN_ADDR);
    time->minute = GM_BCD_TO_HEX(temp) % 60;

    temp = ds3231_read_byte(DS3231_HOUR_ADDR);
    time->hour = GM_BCD_TO_HEX(temp) % 12;
}

/* 设置DS3231时间 */
void ds3231_write_time(gm_time_t *time)
{
    uint8_t temp;

    temp = time->second;
    temp = GM_HEX_TO_BCD(temp);
    ds3231_write_byte(DS3231_SEC_ADDR, temp);

    temp = time->minute;
    temp = GM_HEX_TO_BCD(temp);
    ds3231_write_byte(DS3231_MIN_ADDR, temp);

    temp = time->hour;
    temp = GM_HEX_TO_BCD(temp);
    ds3231_write_byte(DS3231_HOUR_ADDR, temp);
}
